
#include "Debug.h"
#include "Log/log2.h"
#include "simple_protocol.h"
#include <Reader/reader_mfdf.h>
// #include <Reader/ReaderDesfire2.h>
//	#include <Reader/ReaderDesfire.h>

#define API_DESFIRE_CHECK(status)	do{	\
	if(status){							\
		LOG_E("error: %d", status); 	\
		return -1;						\
	}									\
}while(0)


/* extract access right nibbles */
#define MDAR_READ(ar)           (((ar) >> 12) & 0x0F)
#define MDAR_WRITE(ar)          (((ar) >>  8) & 0x0F)
#define MDAR_READ_WRITE(ar)     (((ar) >>  4) & 0x0F)
#define MDAR_CHANGE_AR(ar)      ((ar)         & 0x0F)

/* access right keys -- access right nibble values */
#define MDAR_KEY0              0x00
#define MDAR_KEY1              0x01
#define MDAR_KEY2              0x02
#define MDAR_KEY3              0x03
#define MDAR_KEY4              0x04
#define MDAR_KEY5              0x05
#define MDAR_KEY6              0x06
#define MDAR_KEY7              0x07
#define MDAR_KEY8              0x08
#define MDAR_KEY9              0x09
#define MDAR_KEY10             0x0A
#define MDAR_KEY11             0x0B
#define MDAR_KEY12             0x0C
#define MDAR_KEY13             0x0D
#define MDAR_FREE              0x0E
#define MDAR_DENY              0x0F

typedef __attribute__((packed)) struct {
  uint8_t file_type;
  uint8_t communication_settings;
  uint16_t access_rights;
  
  union {
    struct {
      uint32_t file_size;
    } standard_file;
    struct {
      int32_t lower_limit;
      int32_t upper_limit;
      int32_t limited_credit_value;
      uint8_t limited_credit_enabled;
    } value_file;
    struct {
      uint32_t record_size;
      uint32_t max_number_of_records;
      uint32_t current_number_of_records;
    } record_file;                        /* linear and cyclic record files */
  } settings;
} mifare_desfire_file_settings;

typedef struct {
  struct {
    uint8_t vendor_id;
    uint8_t type;
    uint8_t subtype;
    uint8_t version_major;
    uint8_t version_minor;
    uint8_t storage_size;
    uint8_t protocol;
  } hardware;
  
  struct {
    uint8_t vendor_id;
    uint8_t type;
    uint8_t subtype;
    uint8_t version_major;
    uint8_t version_minor;
    uint8_t storage_size;
    uint8_t protocol;
  } software;
  
  uint8_t uid[7];
  uint8_t batch_number[5];
  uint8_t production_week;
  uint8_t production_year;
} mifare_desfire_version_info;

static inline void desfire_response_result(buffer_t* response, int result){
	uint8_t status = result ? 0 : 1;
	net_buf_simple_push_u8(response, status);
}
/*--------------------------------------------------------------------------------------------------*/
/* save 24-bit little endian data to host memory
 * argument is pointer to memory block
 */
static uint32_t le24toh(uint8_t data[/*3*/])
{
  return ((uint32_t) data[0] | ((uint32_t) data[1] << 8) | 
          ((uint32_t) data[2] << 16));
}

static uint8_t comm_set_2_evx_comm(uint8_t comm_set){
	switch(comm_set){
	case 1: return PHAL_MFDFEVX_COMMUNICATION_MACD;
	case 3: return PHAL_MFDFEVX_COMMUNICATION_ENC;
	}
	return PHAL_MFDFEVX_COMMUNICATION_PLAIN;
}

/*--------------------------------------------------------------------------------------------------*/

static uint32_t *desfire_get_aid_space(buffer_t* response, uint8_t* aid_max_count){
	uint8_t* data = response->data;
	response->data = (uint8_t*)((uint32_t)data & ~(sizeof(uint32_t)-1));
	uint32_t room = net_buf_simple_tailroom(response);
	*aid_max_count = room / sizeof(uint32_t);
	return (uint32_t*) response->data;
}

static void desfire_response_aid(buffer_t* response, uint8_t* aid_buf, uint8_t aid_num, uint8_t aid_max_num){
	uint8_t aid_max_count = 0;
	uint32_t *aids = desfire_get_aid_space(response, &aid_max_count);
	if(aid_max_count > aid_max_num){
		aid_max_count = aid_max_num;
	}
	//add aid count
	net_buf_simple_push_u8(response, aid_num);
	//add aids
	int i;
	for(i = 0; (i < aid_num) && (i < aid_max_count); i++) {
		/* extract AID, which comes in Little Endian */
		aids[i] = le24toh(&aid_buf[3*i]);
	}
	net_buf_simple_add(response, i * sizeof(uint32_t));
	LOG_B("\naids:", response->data, response->len, 16);
}


static int api_desfire_get_application_ids(buffer_t* command, buffer_t* response){
	#pragma pack(1)
	typedef struct {
		uint8_t crypto_env;
		uint8_t max_aid_count;
	}get_application_ids_param_t;
	#pragma pack()
	
	get_application_ids_param_t* param = (get_application_ids_param_t*)command->data;
	uint8_t* aid_buf;
	uint8_t aid_num;
	int ret = reader_mfdf_get_application_ids(PHAL_MFDFEVX_SW_ID, PH_EXCHANGE_DEFAULT, &aid_buf, &aid_num);
	API_DESFIRE_CHECK(ret);
	desfire_response_aid(response, aid_buf, aid_num, param->max_aid_count);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
typedef struct __PACKED  {
	uint8_t CryptoEnv;
	uint32_t AID;
	union __PACKED  {
		struct __PACKED  {
			uint8_t ChangeKeyAccessRights : 4;
			uint8_t ConfigurationChangeable : 1;
			uint8_t FreeCreateDelete : 1;
			uint8_t FreeDirectoryList : 1;
			uint8_t AllowChangeMasterKey : 1;
		}bits;
		uint8_t byte;
	}Settings;
	uint32_t NumberOfKeys;
	uint32_t KeyType;
}create_application_param_t;

static int desfire_create_application(uint32_t aid,          uint8_t settings, uint8_t key_num, uint8_t key_type){
	if(key_num > 14 || key_type > 2){
		return -1;
	}
	uint8_t bKeySettings2 = (key_type << 6) | key_num;
	return reader_mfdf_create_application(PHAL_MFDFEVX_SW_ID, PHAL_MFDFEVX_ISO_FILE_INFO_NOT_AVAILABLE,
			(uint8_t *) &aid, settings, bKeySettings2, 0,
			NULL, NULL, NULL, 0);
}

static int api_desfire_create_application(buffer_t* command, buffer_t* response){
	create_application_param_t* param = (create_application_param_t*)command->data;
	LOG_D("param: aid=%08X, settings=%02X, no_key=%d, key_type=%d", param->AID, param->Settings.byte, param->NumberOfKeys, param->KeyType);
	int ret = desfire_create_application(param->AID, param->Settings.byte, param->NumberOfKeys, param->KeyType);
	API_DESFIRE_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
typedef struct __PACKED  {
	uint8_t CryptoEnv;
	uint32_t AID;
}delete_application_param_t;

static int api_desfire_delete_application(buffer_t* command, buffer_t* response){
	delete_application_param_t* param = (delete_application_param_t*)command->data;
	uint32_t aid = param->AID;
	LOG_D("param: aid=%08X", aid);
	int ret = reader_mfdf_delete_application(PHAL_MFDFEVX_SW_ID, (uint8_t*)&aid, NULL, 0);
	API_DESFIRE_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------------------------*/
static int api_desfire_select_application	(buffer_t* command, buffer_t* response){
	typedef  struct __PACKED {
		uint8_t crypto_env;
		uint32_t aid;
	}select_app_param_t;
	
	select_app_param_t* param = (select_app_param_t*)command->data;
	uint32_t aid = param->aid;
	int ret = reader_mfdf_select_application(PHAL_MFDFEVX_SW_ID, PHAL_MFDFEVX_SELECT_PRIMARY_APP, (uint8_t *)&aid, NULL);
	API_CHECK(ret);
	return ERR_NONE;
}


/*--------------------------------------------------------------------------------------------------*/
/*
Command: [0F04][Byte: CryptoEnv][Byte: KeyNoTag][Byte Array(Var): Key][Byte: KeyType][Byte:
Mode]
Response: [00][Bool: Result]
*/

typedef struct {
	uint8_t CryptoEnv;
	uint8_t KeyNoTag;
	uint8_t KeyLen;
	uint8_t *KeyData;
	uint8_t KeyType;
	uint8_t Mode;
}authenticate_param_t;

static void get_command_param_Authenticate(buffer_t* command, authenticate_param_t *param){
	param->CryptoEnv = net_buf_simple_pull_u8(command);
	param->KeyNoTag = net_buf_simple_pull_u8(command);
	param->KeyLen = net_buf_simple_pull_u8(command);
	param->KeyData = net_buf_simple_pull_mem(command, param->KeyLen);
	param->KeyType = net_buf_simple_pull_u8(command);
	param->Mode = net_buf_simple_pull_u8(command);
}

static int desfire_authenticate(uint8_t crypto_env, uint8_t key_no, uint8_t key_type, 
		uint8_t mode, uint8_t* key_data, uint8_t key_len){
	int ret = -1;
	phStatus_t status;
	uint8_t ver = 0;
	uint8_t keyNo = 1;
	void* key_store = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	
	switch(key_type){
	case 1:{
		PH_CHECK_SUCCESS_FCT(status, phKeyStore_FormatKeyEntry(key_store, 1, PH_KEYSTORE_KEY_TYPE_3K3DES));
		PH_CHECK_SUCCESS_FCT(status, phKeyStore_SetKeyAtPos(key_store, keyNo, 0,
							 PH_KEYSTORE_KEY_TYPE_3K3DES, (uint8_t *)key_data, ver));
		ret = reader_mfdf_authenticate_iso(PHAL_MFDFEVX_SW_ID, PHAL_MFDFEVX_NO_DIVERSIFICATION, keyNo, ver, key_no, NULL, 0);
	}
	break;
	case 2: {
		PH_CHECK_SUCCESS_FCT(status, phKeyStore_FormatKeyEntry(key_store, 1, PH_KEYSTORE_KEY_TYPE_AES128));
		PH_CHECK_SUCCESS_FCT(status, phKeyStore_SetKeyAtPos(key_store, keyNo, 0,
							 PH_KEYSTORE_KEY_TYPE_AES128, (uint8_t *)key_data, ver));
		ret = reader_mfdf_authenticate_aes(PHAL_MFDFEVX_SW_ID, PHAL_MFDFEVX_NO_DIVERSIFICATION, keyNo, ver, key_no, NULL, 0);
	}
	break;
	case 0:	
	default:
		if(key_len > 16){
			return -1;
		}
		if(key_len == 8){
			PH_CHECK_SUCCESS_FCT(status, phKeyStore_FormatKeyEntry(key_store, 1, PH_KEYSTORE_KEY_TYPE_DES));
			PH_CHECK_SUCCESS_FCT(status, phKeyStore_SetKeyAtPos(key_store, keyNo, 0,
								 PH_KEYSTORE_KEY_TYPE_DES, (uint8_t *)key_data, ver));
		}
		else{
			PH_CHECK_SUCCESS_FCT(status, phKeyStore_FormatKeyEntry(key_store, 1, PH_KEYSTORE_KEY_TYPE_2K3DES));
			PH_CHECK_SUCCESS_FCT(status, phKeyStore_SetKeyAtPos(key_store, keyNo, 0,
								 PH_KEYSTORE_KEY_TYPE_2K3DES, (uint8_t *)key_data, ver));
		}
		ret = reader_mfdf_authenticate(PHAL_MFDFEVX_SW_ID, PHAL_MFDFEVX_NO_DIVERSIFICATION, keyNo, ver, key_no, NULL, 0);
		break;
	}
	
	return ret;
}

static int api_desfire_authenticate	(buffer_t* command, buffer_t* response){
	authenticate_param_t param;
	get_command_param_Authenticate(command, &param);
	LOG_D("\nkey_num=%d, key_type=%d, mode=%d", param.KeyNoTag, param.KeyType, param.Mode);
	LOG_B("key:", param.KeyData, param.KeyLen, 16);
	int ret = desfire_authenticate(param.CryptoEnv, param.KeyNoTag, param.KeyType, param.Mode, param.KeyData, param.KeyLen);
	API_CHECK(ret);
	return ERR_NONE;
}


/*--------------------------------------------------------------------------------------------------*/
//API_DESFIRE_GetKeySettings

static int api_desfire_get_key_settings	(buffer_t* command, buffer_t* response){
	uint8_t buf[16];
	uint8_t len;
	int ret = reader_mfdf_get_key_settings(PHAL_MFDFEVX_SW_ID, buf, &len);
	API_CHECK(ret);
	LOG_B("keySettings:", buf, len, 16);
	uint8_t key_settings = buf[0];
	net_buf_simple_add_u8(response, key_settings);
	uint32_t num_of_keys = buf[1] & 0x3F;
	uint32_t key_type = buf[1] >> 6;
	net_buf_simple_add_le32(response, num_of_keys);
	net_buf_simple_add_le32(response, key_type);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//API_DESFIRE_GetFileIDs
typedef struct __PACKED  {
	uint8_t CryptoEnv;
	uint8_t MaxFileIDCount;
}get_file_ids_param_t;

static int api_desfire_get_file_ids	(buffer_t* command, buffer_t* response){
	get_file_ids_param_t* param = (get_file_ids_param_t*)command->data;
	uint8_t count;
	uint8_t* files = net_buf_simple_tail(response);
	int ret = reader_mfdf_get_file_ids(PHAL_MFDFEVX_SW_ID, files, &count);
	API_CHECK(ret);
	if(param->MaxFileIDCount < count){
		count = param->MaxFileIDCount;
	}
	net_buf_simple_push_u8(response, count);
	net_buf_simple_add(response, count);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//API_DESFIRE_GetFileSettings = 7,
static int desfire_get_file_settings(uint8_t file_no, mifare_desfire_file_settings* file_setting)
{
	uint8_t resp_len;
	int ret = reader_mfdf_get_file_settings(PHAL_MFDFEVX_SW_ID, file_no, (uint8_t*)file_setting, &resp_len);
	API_CHECK(ret);
	return 0;
}

static int api_desfire_get_file_settings	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t crypto_env;
		uint8_t file_id;
	}get_file_settings_param_t;
	get_file_settings_param_t *param = (get_file_settings_param_t *)command->data;
	uint8_t* resp_buf = net_buf_simple_tail(response);
	uint8_t resp_len = 0;
	const uint8_t total = 20;
	memset(resp_buf, 0, total);
	int ret = reader_mfdf_get_file_settings(PHAL_MFDFEVX_SW_ID, param->file_id, resp_buf, &resp_len);
	API_CHECK(ret);
	net_buf_simple_add(response, total);
	LOG_B("settings:", response->data, response->len, 16);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//API_DESFIRE_ReadData = 8,

typedef struct {
	uint8_t crypto_env;
	uint8_t file_num;
	uint16_t offset;
	uint8_t length;
	uint8_t comm_set;
}read_data_param_t;

static void desfire_get_read_data_param(buffer_t* command, read_data_param_t *param){
	param->crypto_env = net_buf_simple_pull_u8(command);
	param->file_num = net_buf_simple_pull_u8(command);
	param->offset = net_buf_simple_pull_le16(command);
	param->length = net_buf_simple_pull_u8(command);
	param->comm_set = net_buf_simple_pull_u8(command);
}

static int desfire_get_read_communication_settings(uint8_t file_no, uint8_t comm_set)
{
	switch(comm_set){
	case 1: return PHAL_MFDFEVX_COMMUNICATION_MACD;
	case 3: return PHAL_MFDFEVX_COMMUNICATION_ENC;
	}
	mifare_desfire_file_settings settings;
	uint8_t read_only_access, read_write_access;
	uint8_t* file_setting = (uint8_t*)&settings;
	uint8_t resp_len;
	int ret = reader_mfdf_get_file_settings(PHAL_MFDFEVX_SW_ID, file_no, file_setting, &resp_len);
	API_CHECK(ret);
	phalMfdfEVx_Sw_DataParams_t* palMfdfEVx = (phalMfdfEVx_Sw_DataParams_t *)phNfcLib_GetDataParams(PH_COMP_AL_MFDFEVX);
	read_only_access = MDAR_READ(settings.access_rights);
	read_write_access = MDAR_READ_WRITE(settings.access_rights);

	if((read_only_access != palMfdfEVx->bKeyNo) &&
	 (read_write_access != palMfdfEVx->bKeyNo) &&
	 ((read_only_access == 0x0E) || (read_write_access == 0x0E))) {
		return PHAL_MFDFEVX_COMMUNICATION_PLAIN;
	} else {
		return settings.communication_settings;
	}      
}


static int api_desfire_read_data	(buffer_t* command, buffer_t* response){
	read_data_param_t param;
	desfire_get_read_data_param(command, &param);
	LOG_D("file_num=%u, offset=%u, length=%u, comm_set=%u", param.file_num, param.offset, param.length, param.comm_set);
//		uint8_t *data = net_buf_simple_tail(response);
	uint16_t size = net_buf_simple_tailroom(response);
	if(size <= param.length){
		LOG_E("no space for read");
		return -1;
	}
	int ret = -1;
	int setting = desfire_get_read_communication_settings(param.file_num, param.comm_set);
	if(setting < 0){
		return -1;
	}
	uint8_t offset[3] = {(uint8_t)(param.offset & 0xFF), (uint8_t)(param.offset >> 8), 0x00};
    uint8_t length[3] = {param.length, 0x00, 0x00};
	uint16_t rx_len = 0;
	uint8_t* data = NULL;
	ret = reader_mfdf_read_data(PHAL_MFDFEVX_SW_ID, setting, 0, param.file_num, offset, length, &data, &rx_len);
	API_CHECK(ret);
	net_buf_simple_push_u8(response, rx_len);
	net_buf_simple_add_mem(response, data, rx_len);
	LOG_B("\ndata:", data, rx_len, 16);
	return ERR_NONE;
}


/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_WriteData = 9,
typedef struct __PACKED  {
	uint8_t crypto_env;
	uint8_t file_num;
	uint16_t offset;
	uint8_t length;
	uint8_t data[];
//		uint8_t comm_set;
}write_data_param_t;
static int desfire_get_write_communication_settings(uint8_t file_no, uint8_t comm_set)
{
  switch(comm_set){
  case 1: return PHAL_MFDFEVX_COMMUNICATION_MACD;
  case 3: return PHAL_MFDFEVX_COMMUNICATION_ENC;
  }
  mifare_desfire_file_settings settings;
  uint8_t write_only_access, read_write_access;
  uint8_t* file_setting = (uint8_t*)&settings;
  uint8_t resp_len;
  int ret = reader_mfdf_get_file_settings(PHAL_MFDFEVX_SW_ID, file_no, file_setting, &resp_len);
	API_CHECK(ret);  
  write_only_access = MDAR_WRITE(settings.access_rights);
  read_write_access = MDAR_READ_WRITE(settings.access_rights);
  phalMfdfEVx_Sw_DataParams_t* palMfdfEVx = (phalMfdfEVx_Sw_DataParams_t *)phNfcLib_GetDataParams(PH_COMP_AL_MFDFEVX);
  if((write_only_access != palMfdfEVx->bKeyNo) &&
     (read_write_access != palMfdfEVx->bKeyNo) &&
     ((write_only_access == 0x0E) || (read_write_access == 0x0E))) {
	return PHAL_MFDFEVX_COMMUNICATION_PLAIN;
    
  } else {
    return settings.communication_settings;
  }      
}

static int api_desfire_WriteData	(buffer_t* command, buffer_t* response){
	int ret;
	write_data_param_t* param = (write_data_param_t*)command->data;
	LOG_D("file_num=%u, offset=%u, length=%u, comm_set=%u", 
		param->file_num, param->offset, param->length, param->data[param->length]);
	LOG_B("data", param->data, param->length, 16);
	int setting = desfire_get_write_communication_settings(param->file_num, param->data[param->length]);
	if(setting < 0){
		return -1;
	}
	uint8_t offset[3] = {(uint8_t)(param->offset & 0xFF), (uint8_t)(param->offset >> 8), 0x00};
    uint8_t length[3] = {param->length, 0x00, 0x00};
	ret = reader_mfdf_write_data(PHAL_MFDFEVX_SW_ID, (uint8_t) setting, 0, param->file_num, offset, param->data, length);
	API_CHECK(ret);
	
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_GetValue = 0x0A,
typedef struct __PACKED  {
	uint8_t CryptoEnv;
	uint8_t FileNo;
	uint8_t CommSet;
}GetValue_param_t;

static int api_desfire_GetValue	(buffer_t* command, buffer_t* response){
	int ret;
	GetValue_param_t* param = (GetValue_param_t*)command->data;
	int32_t val;
	int setting = desfire_get_read_communication_settings(param->FileNo, param->CommSet);
	if(setting < 0){
		return -1;
	}
	ret = reader_mfdf_get_value(PHAL_MFDFEVX_SW_ID, setting, param->FileNo, (uint8_t *) &val);
	API_CHECK(ret);
	LOG_D("value=%d", val);
	net_buf_simple_add_le32(response, (uint32_t)val);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_Credit = 0x0B,
typedef struct __PACKED  {
	uint8_t CryptoEnv;
	uint8_t FileNo;
	uint32_t Value;
	uint8_t CommSet;
}Credit_param_t;

static int api_desfire_Credit	(buffer_t* command, buffer_t* response){
	Credit_param_t* param = (Credit_param_t*)command->data;
	LOG_D("value=%d", param->Value);
	int setting = desfire_get_write_communication_settings(param->FileNo, param->CommSet);
	if(setting < 0){
		return -1;
	}
	int ret = reader_mfdf_credit(PHAL_MFDFEVX_SW_ID, (uint8_t)setting, param->FileNo, (uint8_t*)&param->Value);
	API_CHECK(ret);
	return ERR_NONE;
}


/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_Debit = 0x0C,
typedef struct __PACKED  {
	uint8_t CryptoEnv;
	uint8_t FileNo;
	uint32_t Value;
	uint8_t CommSet;
}Debit_param_t;

static int api_desfire_Debit	(buffer_t* command, buffer_t* response){
	Debit_param_t* param = (Debit_param_t*)command->data;
	LOG_D("value=%d", param->Value);
	int setting = desfire_get_write_communication_settings(param->FileNo, param->CommSet);
	if(setting < 0){
		return -1;
	}
	int ret = reader_mfdf_debit(PHAL_MFDFEVX_SW_ID, (uint8_t)setting, param->FileNo, (uint8_t*)&param->Value);
	API_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_LimitedCredit = 0x0D,
typedef struct __PACKED  {
	uint8_t CryptoEnv;
	uint8_t FileNo;
	uint32_t Value;
	uint8_t CommSet;
}LimitedCredit_param_t;

static int api_desfire_LimitedCredit	(buffer_t* command, buffer_t* response){
	LimitedCredit_param_t* param = (LimitedCredit_param_t*)command->data;
	LOG_D("value=%d", param->Value);
	int setting = desfire_get_write_communication_settings(param->FileNo, param->CommSet);
	if(setting < 0){
		return -1;
	}
	int ret = reader_mfdf_limited_credit(PHAL_MFDFEVX_SW_ID, (uint8_t)setting, param->FileNo, (uint8_t*)&param->Value);
	API_CHECK(ret);
	return ERR_NONE;
}


/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_FreeMem = 0x0E,
static int api_desfire_FreeMem	(buffer_t* command, buffer_t* response){
	uint32_t size = 0;
	int ret = reader_mfdf_free_mem(PHAL_MFDFEVX_SW_ID, (uint8_t*)&size);
	API_CHECK(ret);
	LOG_D("size=%d", size);
	net_buf_simple_add_le16(response, (uint16_t)size);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_FormatTag = 0x0F,
static int api_desfire_FormatTag	(buffer_t* command, buffer_t* response){
	int ret = reader_mfdf_format(PHAL_MFDFEVX_SW_ID);
	API_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_CreateDataFile = 0x10,
typedef struct __PACKED  {
	uint8_t CryptoEnv;
	uint8_t FileNo;
	uint8_t FileType;
	uint8_t CommSet;
	uint16_t AccessRights;
	uint32_t FileSize;
}CreateDataFile_param_t;


static int desfire_create_data_file(uint8_t file_no, uint8_t file_type, uint8_t option, uint16_t access_rights, uint32_t file_size){

	if(file_type == 0){
	return reader_mfdf_create_std_data_file(PHAL_MFDFEVX_SW_ID, PHAL_MFDFEVX_ISO_FILE_INFO_NOT_AVAILABLE, 
			file_no, NULL, option, (uint8_t *) &access_rights, (uint8_t *)&file_size);
	}
	else{
	return reader_mfdf_create_backup_data_file(PHAL_MFDFEVX_SW_ID, PHAL_MFDFEVX_ISO_FILE_INFO_NOT_AVAILABLE, 
			file_no, NULL, option, (uint8_t *) &access_rights, (uint8_t *)&file_size);
	}
}

static int api_desfire_CreateDataFile	(buffer_t* command, buffer_t* response){
	CreateDataFile_param_t* param = (CreateDataFile_param_t*)command->data;
	
	LOG_D("FileNo=%u, FileType=%u, CommSet=%u, AccessRights=%04X, FileSize=%u", 
		param->FileNo, param->FileType,param->CommSet,param->AccessRights,
		param->FileSize);
	uint8_t option = param->CommSet;
	int ret = desfire_create_data_file(param->FileNo, param->FileType, option, param->AccessRights, param->FileSize);
	API_CHECK(ret);	
	
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_CreateValueFile = 0x11,
typedef struct __PACKED  {
	uint8_t CryptoEnv;
	uint8_t FileNo;
	uint8_t FileType;
	uint8_t CommSet;
	uint16_t AccessRights;
	uint32_t LowerLimit;
	uint32_t UpperLimit;
	uint32_t LimitedCreditValue;
	uint8_t Settings;
}CreateValueFile_param_t;

static int api_desfire_CreateValueFile	(buffer_t* command, buffer_t* response){
	CreateValueFile_param_t* param = (CreateValueFile_param_t*)command->data;
	
	LOG_D("FileNo=%u, FileType=%u, CommSet=%u, AccessRights=%04X, LowerLimit=%u, UpperLimit=%u," 
			"UpperLimit=%u,LimitedCreditValue=%u,Settings=%02X", 
		param->FileNo, param->FileType,param->CommSet,param->AccessRights,
		param->LowerLimit,param->UpperLimit,param->LimitedCreditValue,param->Settings);
	//TODO: create different file type, settings
	uint8_t setting = param->CommSet;
	int ret = reader_mfdf_create_value_file(PHAL_MFDFEVX_SW_ID, param->FileNo, setting, (uint8_t *)&param->AccessRights, 
		(uint8_t *)&param->LowerLimit, (uint8_t *)&param->UpperLimit, (uint8_t *)&param->LimitedCreditValue, 
		param->Settings & 0x02);
	API_CHECK(ret);
	
	return ERR_NONE;
}


/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_GetVersion = 0x12,
static inline uint32_t desfire_get_storage_size(uint8_t storage_code){
	return (uint32_t)1u << (storage_code >> 1u);
}

static inline uint16_t desfire_get_sorage_code(uint32_t storage_size){
	return (uint16_t)(storage_size / 256);
}

static void desfire_response_version(buffer_t* response, mifare_desfire_version_info* version_info){
	//add hw head info
	net_buf_simple_add_mem(response, &version_info->hardware, 5);
	//add hw size
	uint32_t hw_storage_size = desfire_get_storage_size(version_info->hardware.storage_size);
	net_buf_simple_add_be16(response, desfire_get_sorage_code(hw_storage_size));
	//add protocol
	net_buf_simple_add_be24(response, version_info->hardware.protocol);

	//add sw head info
	net_buf_simple_add_mem(response, &version_info->software, 5);
	uint32_t sw_storage_size = desfire_get_storage_size(version_info->software.storage_size);
	net_buf_simple_add_be16(response, desfire_get_sorage_code(sw_storage_size));
	//add protocol
	net_buf_simple_add_be24(response, version_info->software.protocol);

	//add other info
	net_buf_simple_add_mem(response, version_info->uid, 14);
}

static int api_desfire_get_version	(buffer_t* command, buffer_t* response){
	mifare_desfire_version_info version_info;
	int ret = reader_mfdf_get_version(PHAL_MFDFEVX_SW_ID, (uint8_t *) &version_info);
	API_CHECK(ret);
	desfire_response_version(response, &version_info);
	LOG_B("\nversion:", response->data, response->len, 16);
	return ERR_NONE;
}


/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_DeleteFile = 0x13,
static int api_desfire_DeleteFile	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t CryptoEnv;
		uint8_t FileNo;
	}DeleteFile_param_t;
	DeleteFile_param_t* param = (DeleteFile_param_t*)command->data;
	LOG_D("FileNo = %d", param->FileNo);
	int ret = reader_mfdf_delete_file(PHAL_MFDFEVX_SW_ID, param->FileNo);
	API_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_CommitTransaction = 0x14,
static int api_desfire_CommitTransaction	(buffer_t* command, buffer_t* response){
	uint8_t TMC[4];
	uint8_t TMV[8];
	int ret = reader_mfdf_commit_transaction(PHAL_MFDFEVX_SW_ID, 0, TMC, TMV);
	API_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_AbortTransaction = 0x15,
static int api_desfire_AbortTransaction	(buffer_t* command, buffer_t* response){
	int ret = reader_mfdf_abort_transaction(PHAL_MFDFEVX_SW_ID);
	API_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_GetUID = 0x16,
static int api_desfire_GetUID	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t CryptoEnv;
		uint8_t BufferSize;
	}GetUID_param_t;
	
	GetUID_param_t *param = (GetUID_param_t*)command->data;
	LOG_D("BufferSize = %d", param->BufferSize);
	uint8_t * uid = net_buf_simple_tail(response);
	int ret = reader_mfdf_get_card_uid(PHAL_MFDFEVX_SW_ID, PHAL_MFDFEVX_GET_CARD_UID_EXCHANGE_OPTION_OFF, 
			PHAL_MFDFEVX_GET_CARD_UID_OPTION_NUID_NOT_RETURNED, uid);
	API_CHECK(ret);
	uint8_t ulen = 7;
	if(param->BufferSize < ulen){
		ulen = param->BufferSize;
	}
	net_buf_simple_push_u8(response, ulen);
	net_buf_simple_add(response, ulen);
	LOG_B("\nuid:", response->data, response->len, 16);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_GetKeyVersion = 0x17,
static int api_desfire_GetKeyVersion	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t CryptoEnv;
		uint8_t KeyNo;
	}GetKeyVersion_param_t;
	
	GetKeyVersion_param_t *param = (GetKeyVersion_param_t*)command->data;
	LOG_D("KeyNo = %d", param->KeyNo);
	uint8_t* key_version = net_buf_simple_tail(response);
	uint8_t key_ver_len;
	uint8_t key_no = param->KeyNo & 0x3F;
	int ret;
	
	ret = reader_mfdf_get_key_version(PHAL_MFDFEVX_SW_ID, PHAL_MFDFEVX_KEYSETNO_NOT_PRESENT | key_no, 0, key_version, &key_ver_len);
	API_CHECK(ret);
	net_buf_simple_add(response, key_ver_len);
	LOG_D("version = %02X", key_version[0]);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_ChangeKeySettings = 0x18,

static int api_desfire_ChangeKeySettings	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t CryptoEnv;
		uint8_t Settings;
		uint32_t NumberOfKeys;
		uint32_t KeyType;
	}ChangeKeySettings_param_t;
	
	ChangeKeySettings_param_t *param = (ChangeKeySettings_param_t*)command->data;
	LOG_D("Settings = %02X, NumberOfKeys=%u, KeyType=%u", param->Settings, param->NumberOfKeys, param->KeyType);
	//FIX: 忽略参数
	int ret = reader_mfdf_change_key_settings(PHAL_MFDFEVX_SW_ID, param->Settings);
	API_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_ChangeKey = 0x19,

/*
Command: [0F19][Byte: CryptoEnv][Byte: KeyNo][Byte Array(Var): OldKey][Byte Array(Var):
NewKey][Byte: KeyVersion][4 Bit: ChangeKeyAccessRights][1 Bit: ConfigurationChange-
able][1 Bit: FreeCreateDelete][1 Bit: FreeDirectoryList][1 Bit: AllowChangeMas-
terKey][UInt32: NumberOfKeys][UInt32: KeyType]

Response: [00][Bool: Result]
*/

typedef struct {
	uint8_t CryptoEnv;
	uint8_t KeyNo;
	uint8_t OldKeyLength;
	uint8_t *OldKey;
	uint8_t NewKeyLength;
	uint8_t *NewKey;
	uint8_t KeyVersion;
	uint8_t KeySettings;
	uint32_t NumberOfKeys;
	uint32_t KeyType;
}ChangeKey_param_t;

static void get_command_param_ChangeKey(buffer_t* command, ChangeKey_param_t* param){
	//env
	param->CryptoEnv = net_buf_simple_pull_u8(command);
	//KeyNo
	param->KeyNo = net_buf_simple_pull_u8(command);
	param->OldKeyLength = net_buf_simple_pull_u8(command);
	param->OldKey = net_buf_simple_pull_mem(command, param->OldKeyLength);
	param->NewKeyLength = net_buf_simple_pull_u8(command);
	param->NewKey = net_buf_simple_pull_mem(command, param->NewKeyLength);
	param->KeyVersion = net_buf_simple_pull_u8(command);
	param->KeySettings = net_buf_simple_pull_u8(command);
	param->NumberOfKeys = net_buf_simple_pull_le32(command);
	param->KeyType = net_buf_simple_pull_le32(command);
}

static int desfire_set_keys(ChangeKey_param_t* param, uint16_t wOldKeyNo, uint16_t wNewKeyNo){
	phStatus_t status;
	void* key_store = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	uint8_t key_type;
	uint8_t key_len = param->OldKeyLength;
	int ret = 0;
	
	switch(param->KeyType){
	case 1:{
		key_type = PH_KEYSTORE_KEY_TYPE_3K3DES;
	}
	break;
	case 2: {
		key_type = PH_KEYSTORE_KEY_TYPE_AES128;
	}
	break;
	case 0:	
	default:
		if(key_len > 16){
			return -1;
		}
		if(key_len == 8){
			key_type = PH_KEYSTORE_KEY_TYPE_DES;
		}
		else{
			key_type = PH_KEYSTORE_KEY_TYPE_2K3DES;
		}
		break;
	}
	
	PH_CHECK_SUCCESS_FCT(status, phKeyStore_FormatKeyEntry(key_store, wOldKeyNo, key_type));
	PH_CHECK_SUCCESS_FCT(status, phKeyStore_SetKeyAtPos(key_store, wOldKeyNo, 0, key_type, param->OldKey, 1));
	
	PH_CHECK_SUCCESS_FCT(status, phKeyStore_FormatKeyEntry(key_store, wNewKeyNo, key_type));
	PH_CHECK_SUCCESS_FCT(status, phKeyStore_SetKeyAtPos(key_store, wNewKeyNo, 0, key_type, param->NewKey, 1));
	return ret;
}

static int api_desfire_ChangeKey	(buffer_t* command, buffer_t* response){
	ChangeKey_param_t param;
	
	get_command_param_ChangeKey(command, &param);
	LOG_D("KeyNo=%d, KeyVersion=%d, settings=%02X, NumberOfKeys=%d, KeyType=%d", param.KeyNo, param.KeyVersion, param.KeySettings, param.NumberOfKeys, param.KeyType);
	LOG_B("OldKey", param.OldKey, param.OldKeyLength, 16);
	LOG_B("NewKey", param.NewKey, param.NewKeyLength, 16);
	void* key_store = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	
	uint16_t wOldKeyNo = 1;
	uint16_t wOldKeyVer = 1;
	uint16_t wNewKeyNo = 2;
	uint16_t wNewKeyVer = 1;
	desfire_set_keys(&param, wOldKeyNo, wNewKeyNo);
	int ret;
	ret = reader_mfdf_change_key(PHAL_MFDFEVX_SW_ID, PHAL_MFDFEVX_NO_DIVERSIFICATION, 
		wOldKeyNo, wOldKeyVer, wNewKeyNo, wNewKeyVer, 
		param.KeyNo, NULL, 0);
	API_CHECK(ret);
	return ERR_NONE;
}


/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_ChangeFileSettings = 0x1A,
/*
Command: [0F1A][Byte: CryptoEnv][Byte: FileNo][Byte: NewCommSet][UInt16: OldAccess-
Rights][UInt16: NewAccessRights]

Response: [00][Bool: Result]
*/

static int api_desfire_ChangeFileSettings	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t CryptoEnv;
		uint8_t FileNo;
		uint8_t NewCommSet;
		uint16_t OldAccessRights;
		uint16_t NewAccessRights;
	}ChangeFileSettings_param_t;
	ChangeFileSettings_param_t* param = (ChangeFileSettings_param_t*)command->data;
	//FIX: 
	LOG_D("FileNo=%d, NewCommSet=%02X, OldAccessRights=%04X, NewAccessRights=%04X", 
		param->FileNo, param->NewCommSet, param->OldAccessRights, param->NewAccessRights);
	mifare_desfire_file_settings file_setting;

	if(desfire_get_file_settings(param->FileNo, &file_setting)){
		return -1;
	}
	int ret;
	uint8_t option;
	if (MDAR_CHANGE_AR(file_setting.access_rights) == MDAR_FREE) {
	  /* if ChangeAccessRights Access Rights is set with value "free", no security
	   * mechanism is necessary and therefore the data is sent as plain text
	   */
		option = PHAL_MFDFEVX_COMMUNICATION_MACD;
	} else {
		option = PHAL_MFDFEVX_COMMUNICATION_ENC;
	}
	ret = reader_mfdf_change_file_settings(PHAL_MFDFEVX_SW_ID, option, 
	  param->FileNo, param->NewCommSet, (uint8_t *) &param->NewAccessRights, 0, NULL);
	API_CHECK(ret);	
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_DisableFormatCard = 0x1B,
static int api_desfire_DisableFormatCard	(buffer_t* command, buffer_t* response){
	return -1;
}
/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_EnableRandomID = 0x1C,
static int api_desfire_EnableRandomID	(buffer_t* command, buffer_t* response){
	return -1;
}
/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_SetDefaultKey = 0x1D,
/*
Command: [0F1D][Byte: CryptoEnv][Byte Array(Var): Key][Byte: KeyVersion]

Response: [00][Bool: Result]

@FAIL!!!
*/

static void get_command_param_SetDefaultKey(buffer_t* command, uint8_t * data, uint8_t* data_len){
	//env
	net_buf_simple_pull_u8(command);
	uint8_t klen = net_buf_simple_pull_u8(command);
	memcpy(data, net_buf_simple_pull_mem(command, klen), klen);
	while(klen < 24){
		data[klen] = 0;
		klen++;
	}
	const uint8_t KeyVersion = net_buf_simple_pull_u8(command);
	data[klen] = KeyVersion;
	LOG_D("KeyVersion=%d", KeyVersion);
	LOG_B("Key", data, klen, klen);
	*data_len = klen + 1;
}

static int api_desfire_SetDefaultKey	(buffer_t* command, buffer_t* response){
	uint8_t data[32];
	uint8_t data_len = 0;
	get_command_param_SetDefaultKey(command, data, &data_len);
	/**< Option 1 for updating the Default Keys. */
	int ret = reader_mfdf_set_configuration(PHAL_MFDFEVX_SW_ID, PHAL_MFDFEVX_SET_CONFIG_OPTION1, data, data_len);
	if(ret){
		LOG_E("error: %d", ret);
		return -1;
	}
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_SetATS = 0x1E,
/*
Command: [0F1E][Byte: CryptoEnv][Byte Array(Var): ATS]

Response: [00][Bool: Result]
@FAIL!!!
*/
static int api_desfire_SetATS	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t CryptoEnv;
		uint8_t Length;
		uint8_t ATS[];
	}SetATS_param_t;
	
	SetATS_param_t* param = (SetATS_param_t*)command->data;
	LOG_B("ATS", param->ATS, param->Length, 16);
//		int ret = Reader_Desfire_SetATS(param->ATS);
	/**< Option 2 for updating the ATS. */
	int ret = reader_mfdf_set_configuration(PHAL_MFDFEVX_SW_ID, PHAL_MFDFEVX_SET_CONFIG_OPTION2, param->ATS, param->Length);
	API_DESFIRE_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_CreateRecordFile = 0x1F,
/*
Command: [0F1F][Byte: CryptoEnv][Byte: FileNo][Byte: FileType][Byte: CommSet][UInt16: Access-
Rights][UInt32: RecordSize][UInt32: MaxNumberOfRecords]appending 0‘s]

Response: [00][Bool: Result]
*/

static int api_desfire_CreateRecordFile	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t CryptoEnv;
		uint8_t FileNo;
		uint8_t FileType;
		uint8_t CommSet;
		uint16_t AccessRights;
		uint32_t RecordSize;
		uint32_t MaxNumberOfRecords;
	}CreateRecordFile_param_t;
	
	CreateRecordFile_param_t *param = (CreateRecordFile_param_t*)command->data;
	LOG_D("\nFileNo=%d, FileType=%d, CommSet=%02X, AccessRights=%04X, RecordSize=%d, MaxNumberOfRecords=%d", 
		param->FileNo, param->FileType, param->CommSet, param->AccessRights, param->RecordSize, param->MaxNumberOfRecords);
	uint8_t setting = param->CommSet;
	int ret = reader_mfdf_create_linear_record_file(PHAL_MFDFEVX_SW_ID, PHAL_MFDFEVX_ISO_FILE_INFO_NOT_AVAILABLE, 
		param->FileNo, NULL, setting, (uint8_t *)&param->AccessRights, 
		(uint8_t *) &param->RecordSize, (uint8_t *) &param->MaxNumberOfRecords);
	API_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//API_DESFIRE_ReadRecords = 0x20,
/*
Command: [0F20][Byte: CryptoEnv][Byte: FileNo][UInt16: Offset][Byte: NumberOfRecords][Byte:
RecordSize][Byte: CommSet]

Response: [00][Bool: Result][Byte Array(Var): Data]
@FAIL!!!
*/
static int api_desfire_ReadRecords	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t CryptoEnv;
		uint8_t FileNo;
		uint16_t Offset;
		uint8_t NumberOfRecords;
		uint8_t RecordSize;
		uint8_t CommSet;
	}ReadRecords_param_t;
	ReadRecords_param_t* param = (ReadRecords_param_t*)command->data;
	LOG_D("\nFileNo=%d, Offset=%d, NumberOfRecords=%d, RecordSize=%d, CommSet=%02X", 
		param->FileNo, param->Offset,param->NumberOfRecords, param->RecordSize, param->CommSet);
	uint16_t room = net_buf_simple_tailroom(response);
	uint8_t recordSize = param->RecordSize;
	if(recordSize == 0){
		recordSize = 1;
	}
	uint16_t length = param->NumberOfRecords * recordSize;
	if(room < length){
		LOG_E("no space for read! room=%d, length=%d", room, length);
		return -1;
	}
//		int data_size;
//		uint8_t* data = net_buf_simple_tail(response);
	int setting = desfire_get_read_communication_settings(param->FileNo, param->CommSet);
	if(setting < 0){
		return -1;
	}
	uint8_t record_no[3] = {(uint8_t)(param->Offset & 0xFF), (uint8_t)(param->Offset >> 8)};
	uint8_t record_count[3] = {param->NumberOfRecords};
	uint8_t record_size[3] = {param->RecordSize};
	uint8_t *rec_data = NULL;
	uint16_t rec_len = 0;
	int ret = reader_mfdf_read_records(PHAL_MFDFEVX_SW_ID, (uint8_t)setting, PHAL_MFDFEVX_APPLICATION_CHAINING, param->FileNo, record_no, record_count,
		record_size, &rec_data, &rec_len);
	API_CHECK(ret);
	net_buf_simple_add_u8(response, rec_len);
	net_buf_simple_add_mem(response, rec_data, rec_len);
	LOG_B("\ndata", rec_data, rec_len, 16);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_WriteRecord = 0x21,
/*
Command: [0F21][Byte: CryptoEnv][Byte: FileNo][UInt16: Offset][Byte Array(Var): Data][Byte:
CommSet]

Response: [00][Bool: Result]
*/
typedef struct {
	uint8_t CryptoEnv;
	uint8_t FileNo;
	uint16_t Offset;
	uint8_t Length;
	uint8_t* Data;
	uint8_t CommSet;
}WriteRecord_param_t;

static void api_command_get_param_WriteRecord(buffer_t* command, WriteRecord_param_t* param){
	param->CryptoEnv = net_buf_simple_pull_u8(command);
	param->FileNo = net_buf_simple_pull_u8(command);
	param->Offset = net_buf_simple_pull_le16(command);
	param->Length = net_buf_simple_pull_u8(command);
	param->Data = net_buf_simple_pull_mem(command, param->Length);
	param->CommSet = net_buf_simple_pull_u8(command);
}

static int api_desfire_WriteRecord	(buffer_t* command, buffer_t* response){
	WriteRecord_param_t param;
	api_command_get_param_WriteRecord(command, &param);
	LOG_D("\nFileNo=%d, Offset=%d, Length=%d, CommSet=%02X", param.FileNo, param.Offset,param.Length,param.CommSet);
	LOG_B("\nData", param.Data, param.Length, 16);
	int setting = desfire_get_write_communication_settings(param.FileNo, param.CommSet);
	if(setting < 0){
		LOG_E("get write setting fail!");
		return -1;
	}
//		size_t data_sent;
//		int ret = Reader_Desfire_WriteRecord(param.FileNo, param.Offset, param.Length, param.Data, &data_sent);
	uint8_t offset[3] = {(uint8_t)(param.Offset & 0xFF), (uint8_t)(param.Offset >> 8), 0x00};
    uint8_t length[3] = {param.Length, 0x00, 0x00};
	int ret = reader_mfdf_write_record(PHAL_MFDFEVX_SW_ID, (uint8_t) setting, PHAL_MFDFEVX_APPLICATION_CHAINING, 
		param.FileNo, offset, param.Data, length);
	API_DESFIRE_CHECK(ret);
	return ERR_NONE;
}
/*--------------------------------------------------------------------------------------------------*/
//	API_DESFIRE_ClearRecordFile = 0x22,
/*
Command: [0F22][Byte: CryptoEnv][Byte: FileNo]

Response: [00][Bool: Result
*/
static int api_desfire_ClearRecordFile	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t CryptoEnv;
		uint8_t FileNo;
	}ClearRecordFile_param_t;
	ClearRecordFile_param_t *param = (ClearRecordFile_param_t*)command->data;
	LOG_D("\nFileNo=%d", param->FileNo);	
	int ret = reader_mfdf_clear_record_file(PHAL_MFDFEVX_SW_ID, param->FileNo);
	API_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/


/*--------------------------------------------------------------------------------------------------*/
enum {
	API_DESFIRE_GetApplicationIDs = 0,
	API_DESFIRE_CreateApplication = 1,
	API_DESFIRE_DeleteApplication = 2,
	API_DESFIRE_SelectApplication = 3,
	API_DESFIRE_Authenticate	= 4,
	API_DESFIRE_GetKeySettings = 5,
	API_DESFIRE_GetFileIDs = 6,
	API_DESFIRE_GetFileSettings = 7,
	API_DESFIRE_ReadData = 8,
	API_DESFIRE_WriteData = 9,
	API_DESFIRE_GetValue = 0x0A,
	API_DESFIRE_Credit = 0x0B,
	API_DESFIRE_Debit = 0x0C,
	API_DESFIRE_LimitedCredit = 0x0D,
	API_DESFIRE_FreeMem = 0x0E,
	API_DESFIRE_FormatTag = 0x0F,
	API_DESFIRE_CreateDataFile = 0x10,
	API_DESFIRE_CreateValueFile = 0x11,
	API_DESFIRE_GetVersion = 0x12,
	API_DESFIRE_DeleteFile = 0x13,
	API_DESFIRE_CommitTransaction = 0x14,
	API_DESFIRE_AbortTransaction = 0x15,
	API_DESFIRE_GetUID = 0x16,
	API_DESFIRE_GetKeyVersion = 0x17,
	API_DESFIRE_ChangeKeySettings = 0x18,
	API_DESFIRE_ChangeKey = 0x19,
	API_DESFIRE_ChangeFileSettings = 0x1A,
	API_DESFIRE_DisableFormatCard = 0x1B,
	API_DESFIRE_EnableRandomID = 0x1C,
	API_DESFIRE_SetDefaultKey = 0x1D,
	API_DESFIRE_SetATS = 0x1E,
	API_DESFIRE_CreateRecordFile = 0x1F,
	API_DESFIRE_ReadRecords = 0x20,
	API_DESFIRE_WriteRecord = 0x21,
	API_DESFIRE_ClearRecordFile = 0x22,
	API_DESFIRE_NUM,
};

static const api_entry_t api_desfire_list[API_DESFIRE_NUM] = {
	[API_DESFIRE_GetApplicationIDs] 	= api_desfire_get_application_ids,
	[API_DESFIRE_CreateApplication] 	= api_desfire_create_application,
	[API_DESFIRE_DeleteApplication] 	= api_desfire_delete_application,
	[API_DESFIRE_SelectApplication]		= api_desfire_select_application,
	[API_DESFIRE_Authenticate]			= api_desfire_authenticate,
	[API_DESFIRE_GetKeySettings]		= api_desfire_get_key_settings,
	[API_DESFIRE_GetFileIDs]			= api_desfire_get_file_ids,
	[API_DESFIRE_GetFileSettings]		= api_desfire_get_file_settings,
	[API_DESFIRE_GetVersion] 			= api_desfire_get_version,
	[API_DESFIRE_ReadData]				= api_desfire_read_data,
	[API_DESFIRE_WriteData]			= api_desfire_WriteData,
	[API_DESFIRE_GetValue]			= api_desfire_GetValue,
	[API_DESFIRE_Credit]			= api_desfire_Credit,
	[API_DESFIRE_Debit]				= api_desfire_Debit,
	[API_DESFIRE_LimitedCredit]			= api_desfire_LimitedCredit,
	[API_DESFIRE_FreeMem]			= api_desfire_FreeMem,
	[API_DESFIRE_FormatTag]			= api_desfire_FormatTag,
	[API_DESFIRE_CreateDataFile]			= api_desfire_CreateDataFile,
	[API_DESFIRE_CreateValueFile]			= api_desfire_CreateValueFile,
	[API_DESFIRE_DeleteFile]			= api_desfire_DeleteFile,
	[API_DESFIRE_CommitTransaction]			= api_desfire_CommitTransaction,
	[API_DESFIRE_AbortTransaction]			= api_desfire_AbortTransaction,
	[API_DESFIRE_GetUID]			= api_desfire_GetUID,
	[API_DESFIRE_GetKeyVersion]			= api_desfire_GetKeyVersion,
	[API_DESFIRE_ChangeKeySettings]			= api_desfire_ChangeKeySettings,
	[API_DESFIRE_ChangeKey]			= api_desfire_ChangeKey,
	[API_DESFIRE_ChangeFileSettings]			= api_desfire_ChangeFileSettings,
	[API_DESFIRE_DisableFormatCard]			= api_desfire_DisableFormatCard,
	[API_DESFIRE_EnableRandomID]			= api_desfire_EnableRandomID,
	[API_DESFIRE_SetDefaultKey]			= api_desfire_SetDefaultKey,
	[API_DESFIRE_SetATS]			= api_desfire_SetATS,
	[API_DESFIRE_CreateRecordFile]			= api_desfire_CreateRecordFile,
	[API_DESFIRE_ReadRecords]		 = api_desfire_ReadRecords,
	[API_DESFIRE_WriteRecord]		 = api_desfire_WriteRecord,
	[API_DESFIRE_ClearRecordFile]		 = api_desfire_ClearRecordFile,
};
	
static int desfire_api(buffer_t* command, buffer_t* response){
	const uint8_t num = sizeof(api_desfire_list)/sizeof(api_desfire_list[0]);
	int ret = protocol_call_api(api_desfire_list, num, command, response);
	if(ret > 0){
		return ret;
	}
	desfire_response_result(response, ret);
	return ERR_NONE;
}

SIMPLE_API_DEFINE(API_CLASS_DESFIRE, desfire_api);


